/*
 * tcp_client.h
 *
 *  Created on: 2016-2-27
 *      Author: ZhangXiyin
 */

#ifndef EYAS_SOURCES_IO_SOCKET_TCP_TCP_CLIENT_H_
#define EYAS_SOURCES_IO_SOCKET_TCP_TCP_CLIENT_H_
#include <boost/asio/io_service.hpp>
#include <boost/asio/ip/address.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/placeholders.hpp>
#include <boost/bind.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/thread/recursive_mutex.hpp>
#include "../../conf/def.h"
#include "../../base/connection_base.hpp"
#include "../../base/connection_handler_base.hpp"
#include "tcp_connection.h"
namespace eyas {
namespace io {
template <typename T>
class tcp_client_connection_handler : public connection_handler_base{
public:
	virtual void on_connected(connection_ptr conn_ptr, const error_code& error);
};

class tcp_client: public boost::enable_shared_from_this<tcp_client> {
public:
	tcp_client();
	virtual ~tcp_client();
private:
	tcp_socket_ptr tcpSocketPtr_;
	boost::asio::io_service& ioService_;
	boost::asio::ip::tcp::socket& socket_;
	boost::asio::ip::tcp::endpoint& endpoint_;
	tcp_connection_ptr conn_ptr_;
private:
	void on_connected(const boost::system::error_code &error);

	template<typename F>
	bool _open(const char* ip, unsigned short port, F f);
public:
	// return:true资源开启成功，连接是否成功须通过handler
	bool open(const char* ip, unsigned short port,
			void (*connected_callback)(tcp_connection_ptr const & conn_ptr, const eyas::io::error_code &error));
	template <class T, typename T_Obj>
	bool open(const char* ip, unsigned short port,
			void (T::*connected_callback)(tcp_connection_ptr const & conn_ptr, const eyas::io::error_code &error), T_Obj obj);

	template <typename F, typename... Args>
	bool open(const char* ip, unsigned short port,
			F f,
			Args... args);

	void close();
};

inline bool tcp_client::open(const char* ip, unsigned short port,
		void (*connected_callback)(tcp_connection_ptr const & conn_ptr, const eyas::io::error_code &error)){
	boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::address::from_string(ip), port);
	//this->connHandlerPtr_ = connHandlerPtr;
	this->endpoint_ = endpoint;
	//socket_.set_option(boost::asio::ip::tcp::no_delay(true));
	this->conn_ptr_ = eyas::gc::create_new<tcp_connection>(this->tcpSocketPtr_);
	socket_.async_connect(this->endpoint_,
				boost::bind(connected_callback,
						this->conn_ptr_,
						boost::asio::placeholders::error));
	return true;
}
template <class T, typename T_Obj>
inline bool tcp_client::open(const char* ip, unsigned short port,
		void (T::*connected_callback)(tcp_connection_ptr const & conn_ptr, const eyas::io::error_code &error), T_Obj obj){
	boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::address::from_string(ip), port);
	this->endpoint_ = endpoint;
	this->conn_ptr_ = eyas::gc::create_new<tcp_connection>(this->tcpSocketPtr_);
	socket_.async_connect(this->endpoint_,
				boost::bind(connected_callback,
						obj,
						this->conn_ptr_,
						boost::asio::placeholders::error));
	return true;
}

template <typename F, typename... Args>
inline bool tcp_client::open(const char* ip, unsigned short port,
		F f,
		Args... args){
	boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::address::from_string(ip), port);
	this->endpoint_ = endpoint;
	this->conn_ptr_ = eyas::gc::create_new<tcp_connection>(this->tcpSocketPtr_);
	socket_.async_connect(this->endpoint_,
				boost::bind(f, args...,
						this->conn_ptr_,
						boost::asio::placeholders::error));
	return true;
}

}
}
#endif /* EYAS_SOURCES_IO_SOCKET_TCP_TCP_CLIENT_H_ */
